using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Text.RegularExpressions;

namespace IppServer.Host.Configuration
{
    /// <summary>
    /// IP/MAC地址验证器
    /// </summary>
    internal static class IpMacValidator
    {
        private static readonly Regex CidrRegex = new Regex(@"^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$", RegexOptions.Compiled);
        private static readonly Regex IpRangeRegex = new Regex(@"^(\d{1,3}\.){3}\d{1,3}-(\d{1,3}\.){3}\d{1,3}$", RegexOptions.Compiled);
        private static readonly Regex MacRegex = new Regex(@"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}|\*)$|^([0-9A-Fa-f]{2}[:-]){0,5}\*$", RegexOptions.Compiled);

        /// <summary>
        /// 获取合适的控制台输出编码
        /// netsh和arp等Windows命令行工具的输出始终使用系统代码页（中文Windows通常是GBK）
        /// 不管Windows版本如何，都应该使用系统默认编码
        /// </summary>
        private static Encoding GetConsoleOutputEncoding()
        {
            // netsh和arp等Windows命令行工具的输出始终使用系统代码页
            // 在中文Windows系统中，系统代码页通常是GBK（代码页936）
            // 因此统一使用Encoding.Default，它会自动使用系统代码页
            return Encoding.Default;
        }

        /// <summary>
        /// 验证IP/MAC地址是否被允许访问
        /// </summary>
        /// <param name="restriction">限制配置</param>
        /// <param name="clientIp">客户端IP地址</param>
        /// <param name="clientMac">客户端MAC地址（可选，如果无法获取则为null）</param>
        /// <param name="denyReason">如果被拒绝，返回拒绝原因</param>
        /// <returns>true=允许访问，false=拒绝访问</returns>
        public static bool IsAllowed(IpMacRestriction restriction, string clientIp, string clientMac, out string denyReason)
        {
            denyReason = null;

            // 如果未启用限制，允许所有访问
            if (restriction == null || !restriction.Enabled)
            {
                return true;
            }

            // 验证IP地址
            bool ipMatched = false;
            if (!string.IsNullOrWhiteSpace(clientIp) && restriction.IpRules != null && restriction.IpRules.Count > 0)
            {
                foreach (var rule in restriction.IpRules)
                {
                    if (MatchIpRule(clientIp, rule))
                    {
                        ipMatched = true;
                        break;
                    }
                }
            }

            // 验证MAC地址
            bool macMatched = false;
            if (!string.IsNullOrWhiteSpace(clientMac) && restriction.MacRules != null && restriction.MacRules.Count > 0)
            {
                foreach (var rule in restriction.MacRules)
                {
                    if (MatchMacRule(clientMac, rule))
                    {
                        macMatched = true;
                        break;
                    }
                }
            }

            // 判断是否匹配（IP或MAC任一匹配即视为匹配）
            bool matched = ipMatched || macMatched;

            // 白名单模式：只有匹配的才允许
            if (restriction.WhitelistMode)
            {
                if (!matched)
                {
                    denyReason = $"IP地址 {clientIp} 不在白名单中";
                    return false;
                }
                return true;
            }
            // 黑名单模式：匹配的拒绝
            else
            {
                if (matched)
                {
                    if (ipMatched)
                    {
                        denyReason = $"IP地址 {clientIp} 在黑名单中";
                    }
                    else if (macMatched)
                    {
                        denyReason = $"MAC地址 {clientMac} 在黑名单中";
                    }
                    return false;
                }
                return true;
            }
        }

        /// <summary>
        /// 匹配IP规则
        /// </summary>
        private static bool MatchIpRule(string ip, string rule)
        {
            if (string.IsNullOrWhiteSpace(rule) || string.IsNullOrWhiteSpace(ip))
            {
                return false;
            }

            rule = rule.Trim();
            ip = ip.Trim();

            // 精确匹配
            if (rule.Equals(ip, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            // CIDR网段匹配（如：192.168.1.0/24）
            if (CidrRegex.IsMatch(rule))
            {
                try
                {
                    var parts = rule.Split('/');
                    var networkIp = IPAddress.Parse(parts[0]);
                    var prefixLength = int.Parse(parts[1]);
                    return IsIpInCidr(ip, networkIp, prefixLength);
                }
                catch
                {
                    return false;
                }
            }

            // IP范围匹配（如：192.168.1.1-192.168.1.100）
            if (IpRangeRegex.IsMatch(rule))
            {
                try
                {
                    var parts = rule.Split('-');
                    var startIp = IPAddress.Parse(parts[0].Trim());
                    var endIp = IPAddress.Parse(parts[1].Trim());
                    return IsIpInRange(ip, startIp, endIp);
                }
                catch
                {
                    return false;
                }
            }

            return false;
        }

        /// <summary>
        /// 标准化MAC地址格式（统一为冒号分隔的6组2位十六进制格式）
        /// 支持多种输入格式：
        /// - xxxxxxxxxxxx（12位连续字符）
        /// - xxxx-xxxx-xxxx（每4位一组）
        /// - xxxx:xxxx:xxxx（每4位一组）
        /// - xx-xx-xx-xx-xx-xx（每2位一组，已支持）
        /// - xx:xx:xx:xx:xx:xx（每2位一组，已支持）
        /// </summary>
        public static string NormalizeMacAddress(string mac)
        {
            if (string.IsNullOrWhiteSpace(mac))
            {
                return null;
            }

            mac = mac.Trim().ToUpperInvariant();
            
            // 移除所有分隔符
            var cleanMac = mac.Replace(":", "").Replace("-", "").Replace(".", "").Replace(" ", "");
            
            // 如果包含通配符，先处理通配符情况
            if (mac.Contains("*"))
            {
                // 如果是12位字符（可能包含通配符），转换为标准格式
                if (cleanMac.Length == 12 && System.Text.RegularExpressions.Regex.IsMatch(cleanMac, @"^([0-9A-F*]{2}){6}$"))
                {
                    return $"{cleanMac.Substring(0, 2)}:{cleanMac.Substring(2, 2)}:{cleanMac.Substring(4, 2)}:{cleanMac.Substring(6, 2)}:{cleanMac.Substring(8, 2)}:{cleanMac.Substring(10, 2)}";
                }
                
                // 如果是每2位一组的格式（包含通配符），统一为冒号分隔
                if (System.Text.RegularExpressions.Regex.IsMatch(mac, @"^([0-9A-F*]{2}[:-]){5}([0-9A-F*]{2})$"))
                {
                    return mac.Replace("-", ":");
                }
            }
            
            // 如果是12位连续字符（不含通配符），转换为标准格式
            if (cleanMac.Length == 12 && System.Text.RegularExpressions.Regex.IsMatch(cleanMac, @"^[0-9A-F]{12}$"))
            {
                return $"{cleanMac.Substring(0, 2)}:{cleanMac.Substring(2, 2)}:{cleanMac.Substring(4, 2)}:{cleanMac.Substring(6, 2)}:{cleanMac.Substring(8, 2)}:{cleanMac.Substring(10, 2)}";
            }
            
            // 如果是每4位一组的格式（xxxx-xxxx-xxxx 或 xxxx:xxxx:xxxx）
            if (System.Text.RegularExpressions.Regex.IsMatch(mac, @"^([0-9A-F]{4}[:-]){2}[0-9A-F]{4}$"))
            {
                var parts = mac.Split(new[] { ':', '-' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length == 3 && parts[0].Length == 4 && parts[1].Length == 4 && parts[2].Length == 4)
                {
                    return $"{parts[0].Substring(0, 2)}:{parts[0].Substring(2, 2)}:{parts[1].Substring(0, 2)}:{parts[1].Substring(2, 2)}:{parts[2].Substring(0, 2)}:{parts[2].Substring(2, 2)}";
                }
            }
            
            // 如果是每2位一组的格式（xx:xx:xx:xx:xx:xx 或 xx-xx-xx-xx-xx-xx）
            if (System.Text.RegularExpressions.Regex.IsMatch(mac, @"^([0-9A-F]{2}[:-]){5}[0-9A-F]{2}$"))
            {
                return mac.Replace("-", ":");
            }
            
            return null;
        }

        /// <summary>
        /// 匹配MAC规则（支持通配符）
        /// </summary>
        private static bool MatchMacRule(string mac, string rule)
        {
            if (string.IsNullOrWhiteSpace(rule) || string.IsNullOrWhiteSpace(mac))
            {
                return false;
            }

            // 标准化MAC地址格式
            var normalizedMac = NormalizeMacAddress(mac);
            var normalizedRule = NormalizeMacAddress(rule);
            
            if (normalizedMac == null || normalizedRule == null)
            {
                return false;
            }

            // 精确匹配
            if (normalizedRule.Equals(normalizedMac, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            // 通配符匹配（如：00:11:22:*:*:*）
            if (normalizedRule.Contains("*"))
            {
                var ruleParts = normalizedRule.Split(':');
                var macParts = normalizedMac.Split(':');

                if (ruleParts.Length != macParts.Length || ruleParts.Length != 6)
                {
                    return false;
                }

                for (int i = 0; i < ruleParts.Length; i++)
                {
                    if (ruleParts[i] != "*" && !ruleParts[i].Equals(macParts[i], StringComparison.OrdinalIgnoreCase))
                    {
                        return false;
                    }
                }
                return true;
            }

            return false;
        }

        /// <summary>
        /// 检查IP是否在CIDR网段内
        /// </summary>
        private static bool IsIpInCidr(string ip, IPAddress networkIp, int prefixLength)
        {
            try
            {
                var clientIp = IPAddress.Parse(ip);
                var networkBytes = networkIp.GetAddressBytes();
                var clientBytes = clientIp.GetAddressBytes();

                if (networkBytes.Length != clientBytes.Length)
                {
                    return false;
                }

                var bytesToCheck = prefixLength / 8;
                var bitsToCheck = prefixLength % 8;

                // 检查完整字节
                for (int i = 0; i < bytesToCheck; i++)
                {
                    if (networkBytes[i] != clientBytes[i])
                    {
                        return false;
                    }
                }

                // 检查部分字节
                if (bitsToCheck > 0 && bytesToCheck < networkBytes.Length)
                {
                    var mask = (byte)(0xFF << (8 - bitsToCheck));
                    if ((networkBytes[bytesToCheck] & mask) != (clientBytes[bytesToCheck] & mask))
                    {
                        return false;
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 检查IP是否在范围内
        /// </summary>
        private static bool IsIpInRange(string ip, IPAddress startIp, IPAddress endIp)
        {
            try
            {
                var clientIp = IPAddress.Parse(ip);
                var clientBytes = clientIp.GetAddressBytes();
                var startBytes = startIp.GetAddressBytes();
                var endBytes = endIp.GetAddressBytes();

                if (clientBytes.Length != startBytes.Length || clientBytes.Length != endBytes.Length)
                {
                    return false;
                }

                // 将IP地址转换为整数进行比较
                long clientValue = IpToLong(clientBytes);
                long startValue = IpToLong(startBytes);
                long endValue = IpToLong(endBytes);

                return clientValue >= startValue && clientValue <= endValue;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 将IP地址字节数组转换为长整数
        /// </summary>
        private static long IpToLong(byte[] bytes)
        {
            long result = 0;
            for (int i = 0; i < bytes.Length; i++)
            {
                result = (result << 8) | bytes[i];
            }
            return result;
        }

        /// <summary>
        /// 根据IP地址获取MAC地址（通过ARP表）
        /// </summary>
        public static string GetMacAddressFromIp(string ipAddress)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(ipAddress))
                {
                    return null;
                }

                // 尝试解析IP地址
                if (!IPAddress.TryParse(ipAddress, out var ip))
                {
                    return null;
                }

                // 跳过回环地址
                if (IPAddress.IsLoopback(ip))
                {
                    return null;
                }

                // 使用ARP表查找MAC地址
                var arpTable = GetArpTable();
                if (arpTable.TryGetValue(ipAddress, out var mac))
                {
                    // 确保MAC地址格式标准化（统一为冒号分隔，大写）
                    if (!string.IsNullOrWhiteSpace(mac))
                    {
                        mac = mac.ToUpperInvariant().Replace("-", ":");
                        // 验证格式
                        if (Regex.IsMatch(mac, @"^([0-9A-F]{2}:){5}[0-9A-F]{2}$"))
                        {
                            return mac;
                        }
                    }
                }
            }
            catch
            {
                // 忽略错误，返回null
            }

            return null;
        }

        /// <summary>
        /// 获取ARP表（IP -> MAC映射）
        /// 通过执行 arp -a 命令获取系统ARP表
        /// </summary>
        private static Dictionary<string, string> GetArpTable()
        {
            var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            try
            {
                // 使用 arp -a 命令获取ARP表
                var consoleEncoding = GetConsoleOutputEncoding();
                var processInfo = new ProcessStartInfo
                {
                    FileName = "arp",
                    Arguments = "-a",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true,
                    StandardOutputEncoding = consoleEncoding,
                    StandardErrorEncoding = consoleEncoding
                };

                using (var process = Process.Start(processInfo))
                {
                    if (process == null)
                    {
                        return result;
                    }

                    var output = process.StandardOutput.ReadToEnd();
                    process.WaitForExit(3000);

                    // 解析 arp -a 输出
                    // Windows格式示例（中文）：
                    //   接口: 192.168.1.100 --- 0x3
                    //     Internet 地址          物理地址              类型
                    //     192.168.1.1           00-11-22-33-44-55     动态
                    //     192.168.1.2           aa-bb-cc-dd-ee-ff     动态
                    // Windows格式示例（英文）：
                    //   Interface: 192.168.1.100 --- 0x3
                    //     Internet Address      Physical Address      Type
                    //     192.168.1.1           00-11-22-33-44-55     dynamic
                    //     192.168.1.2           aa-bb-cc-dd-ee-ff     dynamic
                    var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var line in lines)
                    {
                        var trimmed = line.Trim();
                        if (string.IsNullOrWhiteSpace(trimmed) || 
                            trimmed.StartsWith("接口:", StringComparison.OrdinalIgnoreCase) || 
                            trimmed.StartsWith("Interface:", StringComparison.OrdinalIgnoreCase) ||
                            trimmed.StartsWith("Internet", StringComparison.OrdinalIgnoreCase) || 
                            trimmed.StartsWith("---", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        // 解析行：IP地址 MAC地址 类型
                        // 使用正则表达式匹配：IP地址（可选空格）MAC地址（可选空格）类型
                        // 支持MAC地址使用冒号或连字符分隔
                        var match = Regex.Match(trimmed, @"^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+([0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2}[:-][0-9A-Fa-f]{2})", RegexOptions.IgnoreCase);
                        if (match.Success && match.Groups.Count >= 3)
                        {
                            var ip = match.Groups[1].Value;
                            var mac = match.Groups[2].Value.ToUpperInvariant().Replace("-", ":");
                            
                            // 验证MAC地址格式（统一为冒号分隔，大写）
                            if (Regex.IsMatch(mac, @"^([0-9A-F]{2}:){5}[0-9A-F]{2}$"))
                            {
                                result[ip] = mac;
                            }
                        }
                    }
                }
            }
            catch
            {
                // 忽略错误，返回空字典
            }

            return result;
        }

        /// <summary>
        /// 验证IP规则格式是否有效
        /// </summary>
        public static bool ValidateIpRule(string rule, out string errorMessage)
        {
            errorMessage = null;

            if (string.IsNullOrWhiteSpace(rule))
            {
                errorMessage = "规则不能为空";
                return false;
            }

            rule = rule.Trim();

            // 检查是否为单个IP地址
            if (IPAddress.TryParse(rule, out _))
            {
                return true;
            }

            // 检查是否为CIDR格式
            if (CidrRegex.IsMatch(rule))
            {
                try
                {
                    var parts = rule.Split('/');
                    if (!IPAddress.TryParse(parts[0], out _))
                    {
                        errorMessage = "CIDR格式中的IP地址无效";
                        return false;
                    }
                    if (!int.TryParse(parts[1], out var prefix) || prefix < 0 || prefix > 32)
                    {
                        errorMessage = "CIDR前缀长度必须在0-32之间";
                        return false;
                    }
                    return true;
                }
                catch
                {
                    errorMessage = "CIDR格式无效";
                    return false;
                }
            }

            // 检查是否为IP范围格式
            if (IpRangeRegex.IsMatch(rule))
            {
                try
                {
                    var parts = rule.Split('-');
                    if (!IPAddress.TryParse(parts[0].Trim(), out var startIp))
                    {
                        errorMessage = "IP范围起始地址无效";
                        return false;
                    }
                    if (!IPAddress.TryParse(parts[1].Trim(), out var endIp))
                    {
                        errorMessage = "IP范围结束地址无效";
                        return false;
                    }
                    // 检查起始IP是否小于等于结束IP
                    var startBytes = startIp.GetAddressBytes();
                    var endBytes = endIp.GetAddressBytes();
                    for (int i = 0; i < startBytes.Length; i++)
                    {
                        if (startBytes[i] > endBytes[i])
                        {
                            errorMessage = "起始IP地址必须小于等于结束IP地址";
                            return false;
                        }
                        if (startBytes[i] < endBytes[i])
                        {
                            break;
                        }
                    }
                    return true;
                }
                catch
                {
                    errorMessage = "IP范围格式无效";
                    return false;
                }
            }

            errorMessage = "IP规则格式无效，支持：单个IP、CIDR网段（如192.168.1.0/24）、IP范围（如192.168.1.1-192.168.1.100）";
            return false;
        }

        /// <summary>
        /// 验证MAC规则格式是否有效
        /// 支持多种格式：
        /// - xxxxxxxxxxxx（12位连续字符）
        /// - xxxx-xxxx-xxxx（每4位一组）
        /// - xxxx:xxxx:xxxx（每4位一组）
        /// - xx-xx-xx-xx-xx-xx（每2位一组）
        /// - xx:xx:xx:xx:xx:xx（每2位一组）
        /// - 支持通配符（如00:11:22:*:*:*）
        /// </summary>
        public static bool ValidateMacRule(string rule, out string errorMessage)
        {
            errorMessage = null;

            if (string.IsNullOrWhiteSpace(rule))
            {
                errorMessage = "规则不能为空";
                return false;
            }

            // 尝试标准化MAC地址格式
            var normalized = NormalizeMacAddress(rule);
            if (normalized == null)
            {
                errorMessage = "MAC规则格式无效，支持：完整MAC地址（如00:11:22:33:44:55或001122334455）或带通配符的MAC地址（如00:11:22:*:*:*）";
                return false;
            }

            // 检查标准化后的格式
            var parts = normalized.Split(':');
            if (parts.Length == 6)
            {
                // 检查每个部分（非通配符部分必须是有效的十六进制）
                foreach (var part in parts)
                {
                    if (part != "*" && !System.Text.RegularExpressions.Regex.IsMatch(part, @"^[0-9A-F]{2}$"))
                    {
                        errorMessage = "MAC地址格式无效，每个字节必须是两位十六进制数或通配符*";
                        return false;
                    }
                }
                return true;
            }

            errorMessage = "MAC规则格式无效，支持：完整MAC地址（如00:11:22:33:44:55或001122334455）或带通配符的MAC地址（如00:11:22:*:*:*）";
            return false;
        }
    }
}

